<?php

namespace App\Services;

use App\Models\WxMenu;
use Illuminate\Support\Facades\DB;

/**
 * 微信菜单服务类
 * @package App\Services
 */
class WxMenuService
{
    //菜单类别
    private $typeList = [
        'click' => '点击',
        'view' => '网页',
        'miniprogram' => '小程序',
        'scancode_push' => '扫码推事件',
        'scancode_waitmsg' => '扫码带提示',
        'pic_sysphoto' => '系统拍照发图',
        'pic_photo_or_album' => '拍照或者相册发图',
        'pic_weixin' => '微信相册发图',
        'location_select' => '发送位置',
        'media_id' => '图片',
        'view_limited' => '图文消息',
    ];
    private $sexList = [1 => '男', 2 => '女',];//性别列表
    private $clientPlatformList = [1 => 'IOS', 2 => 'Android', 3 => 'Others'];//客户端版本列表
    //客户端语言列表
    private $lannguageList = [
        "zh_CN" => '简体中文', "zh_TW" => '繁体中文TW', "zh_HK" => '繁体中文HK', "en" => '英文',
        "id" => '印尼', "ms" => '马来', "es" => '西班牙', "ko" => '韩国', "it" => '意大利', "ja" => '日本',
        "pl" => '波兰', "pt" => '葡萄牙', "ru" => '俄国', "th" => '泰文', "vi" => '越南',
        "ar" => '阿拉伯语', "hi" => '北印度', "he" => '希伯来', "tr" => '土耳其', "de" => '德语', "fr" => '法语'
    ];

    /**
     * 构造函数
     */
    public function __construct()
    {

    }

    /**
     * 获取菜单列表
     * @return \Illuminate\Database\Eloquent\Collection|static[]
     */
    public function getMenuList()
    {
        $tagList = WxMenu::all();
        return $tagList;
    }

    /**
     * 获取菜单类别
     * @return array
     */
    public function getTypeList()
    {
        return $this->typeList;
    }

    /**
     * 获取个性化菜单类别名称
     * @param $type
     * @return mixed|string
     */
    public function getTypeName($type)
    {
        return isset($this->typeList[$type]) ? $this->typeList[$type] : '未知';
    }

    /**
     * 获取性别列表
     * @return array
     */
    public function getSexList()
    {
        return $this->sexList;
    }

    /**
     * 获取客户端列表
     * @return array
     */
    public function getClientPlatformList()
    {
        return $this->clientPlatformList;
    }

    /**
     * 获取语言列表
     * @return array
     */
    public function getLanguageList()
    {
        return $this->lannguageList;
    }

    /**
     * 保存菜单数据
     * @param $request
     * @return bool
     * @throws \Exception
     */
    public function save($request)
    {
        if (empty($request->menu_id)){
            $menuModel = new WxMenu;
        }else{
            $menuModel = WxMenu::findOrFail($request->menu_id);
        }
        $menuModel->parent_id = $request->parent_id ?? 0;
        $menuModel->name = $request->name ?? '';
        $menuModel->type = $request->type ?? '';
        $menuModel->key = $request->key ?? '';
        $menuModel->url = $request->url ?? '';
        $menuModel->appid = $request->appid ?? '';
        $menuModel->pagepath = $request->pagepath ?? '';
        $menuModel->media_id = $request->media_id ?? '';
        $menuModel->order_num = $request->order_num ?? 0;
        $menuModel->is_conditional = $request->is_conditional ?? 0;
        //个性化规则
        $matchrule = [];
        !empty($request->tag_id) && $matchrule['tag_id'] = $request->tag_id;
        !empty($request->sex) && $matchrule['sex'] = $request->sex;
        if (!empty($request->countryId)){
            $matchrule['countryId'] = $request->countryId;
            $matchrule['country'] = $request->country;
        }
        if (!empty($request->provinceId)){
            $matchrule['provinceId'] = $request->provinceId;
            $matchrule['province'] = $request->province;
        }
        if (!empty($request->cityId)){
            $matchrule['cityId'] = $request->cityId;
            $matchrule['city'] = $request->city;
        }
        !empty($request->client_platform_type) && $matchrule['client_platform_type'] = $request->client_platform_type;
        !empty($request->language) && $matchrule['language'] = $request->language;
        if ($menuModel->is_conditional == 1 && empty($matchrule)) {
            throw new \Exception('请设置个性化规则');
        }
        $menuModel->matchrule = $matchrule;
        if ($menuModel->menu_id == $menuModel->parent_id){
            throw new \Exception('不能设置当前菜单为父级菜单');
        }
        return $menuModel->save();
    }

    /**
     * 删除菜单
     * @param $id
     * @return int
     */
    public function del($id)
    {
        $find = WxMenu::findOrFail($id);
        return $find->delete();
    }

    /**
     * 获取按个性化菜单规则分组的菜单列表
     * @return array
     */
    private function getGroupListByRuleKey()
    {
        //菜单原始列表
        $menuList = $this->getMenuList()->toArray();
        $normalMenuList = [];
        $conditionalMenuList = [];
        //抽离出普通菜单和个性化菜单
        foreach ($menuList as $menuData) {
            if ($menuData['is_conditional'] && $menuData['matchrule']) {
                $matchRule = $menuData['matchrule'];
                unset($matchRule['countryId'], $matchRule['provinceId'], $matchRule['cityId']);
                ksort($matchRule);
                $menuData['matchrule'] = $matchRule;
                $conditionalMenuList[] = $menuData;
            } else {
                unset($menuData['matchrule']);
                $normalMenuList[] = $menuData;
            }
        }
        //按照不同的个性化规则分成不同的菜单组合，这样避免重复创建菜单
        $ruleGroupMenuList = [];
        $ruleGroupMenuList['default']['list'] = $normalMenuList;
        foreach ($conditionalMenuList as $menuData) {
            $matchRule = $menuData['matchrule'];
            $key = md5(json_encode($matchRule));
            //如果为创建个性化，则用普通菜单初始化，并且把个性化菜单放进来
            if (!isset($ruleGroupMenuList[$key])) {
                $ruleGroupMenuList[$key]['list'] = $normalMenuList;
                $ruleGroupMenuList[$key]['matchrule'] = $matchRule;
            }
            $ruleGroupMenuList[$key]['list'][] = $menuData;
        }

        return $ruleGroupMenuList;
    }
    /**
     * 根据菜单类别过滤掉一些不必要的菜单数据
     * @param $menuData
     * @return array
     */
    private function filterMenuData($menuData)
    {
        $newMenuData = [];
        $newMenuData['type'] = $menuData['type'] ?? 'click';
        $newMenuData['name'] = $menuData['name'] ?? '';
        if (in_array($newMenuData['type'], ['click', 'scancode_waitmsg', 'scancode_push', 'pic_sysphoto', 'pic_photo_or_album', 'pic_weixin', 'location_select'])) {
            $newMenuData['key'] = $menuData['key'] ?? '';
        } else if (in_array($newMenuData['type'], ['view'])) {
            $newMenuData['url'] = $menuData['url'] ?? '';
        } else if (in_array($newMenuData['type']['miniprogram'])) {
            $newMenuData['url'] = $menuData['url'] ?? '';
            $newMenuData['appid'] = $menuData['appid'] ?? '';
            $newMenuData['pagepath'] = $menuData['pagepath'] ?? '';
        }
        return $newMenuData;
    }
    /**
     * 格式化为微信菜单格式
     * @param $menuButtonList
     * @return array|void
     * @throws \Exception
     */
    private function formatButtons($menuButtonList)
    {
        if (!$menuButtonList) {
            return;
        }
        $buttons = [];
        //排序
        $menu = sortArrByManyField($menuButtonList, 'order_num', SORT_ASC, 'menu_id', SORT_ASC);
        $menu = array_slice($menu, 0, 3);
        foreach ($menu as $index => $val) {
            $buttons[$index] = $this->filterMenuData($val);
            if (!empty($val['sub_button'])) {//有子菜单
                //排序
                $val['sub_button'] = sortArrByManyField($val['sub_button'], 'order_num', SORT_ASC, 'menu_id', SORT_ASC);
                $val['sub_button'] = array_slice($val['sub_button'], 0, 5);

                foreach ($val['sub_button'] as $subVal) {
                    $buttons[$index]['sub_button'][] = $this->filterMenuData($subVal);
                }
                unset($buttons[$index]['type']);
            }
        }
        return $buttons;
    }

    /**
     * 发布菜单
     * @return bool
     * @throws \Exception
     */
    public function publish()
    {
        $ruleGroupMenuList = $this->getGroupListByRuleKey();
        if (!$ruleGroupMenuList) {
            throw new \Exception('微信菜单为空');
        }
        $app = EasyWechat::officialAccount();
        //删除所有菜单
        $app->menu->delete();
        //同步WX自定义菜单
        foreach ($ruleGroupMenuList as $menuData) {
            $buttons = listToTree($menuData['list'], 'menu_id', 'parent_id', 'sub_button', 0);
            $buttons = $this->formatButtons($buttons);
            if (isset($menuData['matchrule'])) {
                $apiRs = $app->menu->create($buttons, $menuData['matchrule']);
            } else {
                $apiRs = $app->menu->create($buttons);
            }
            //检查微信接口返回结果
            WxErrorService::checkApiResponse($apiRs);
        }
        return true;
    }

    /**
     * 同步线上数据
     * @return bool
     * @throws \Exception
     */
    public function sync()
    {
        $app = EasyWechat::officialAccount();
        $apiRs = $app->menu->list();
        //检查微信接口返回结果
        WxErrorService::checkApiResponse($apiRs);
        $list = [];
        //普通菜单
        if (!empty($apiRs['menu']['button'])){
            foreach ($apiRs['menu']['button'] as $index1 => $menu1){
                $key1 = empty($menu1['sub_button']) ? $menu1['name'].'_'.$menu1['type'] : $menu1['name'];
                $list[$key1] = $this->filterMenuData($menu1);
                $list[$key1]['order_num'] = $index1;
                if (!empty($menu1['sub_button'])){//存在子菜单
                    foreach ($menu1['sub_button'] as $index2 => $menu2) {
                        $key2 = $menu2['name'].'_'.$menu2['type'];
                        $sub_button = $this->filterMenuData($menu2);
                        $sub_button['order_num'] = $index2;
                        $list[$key1]['sub_button'][$key2] = $sub_button;
                    }
                }
            }
        }
        //个性化菜单
        if (!empty($apiRs['conditionalmenu'])){
            $wxAreaSer = new WxAreaService();
            foreach ($apiRs['conditionalmenu'] as $menuGroup){
                $matchrule = $menuGroup['matchrule'] ?? [];
                !empty($matchrule['country']) && $matchrule['countryId'] = $wxAreaSer->getIdByName($matchrule['country']);
                !empty($matchrule['province']) && $matchrule['provinceId'] = $wxAreaSer->getIdByName($matchrule['province']);
                !empty($matchrule['city']) && $matchrule['cityId'] = $wxAreaSer->getIdByName($matchrule['city']);
                $menuGroup['matchrule'] = $matchrule;

                if (!empty($menuGroup['button'])){
                    foreach ($menuGroup['button'] as $index1 => $menu1){
                        $key1 = empty($menu1['sub_button']) ? $menu1['name'].'_'.$menu1['type'] : $menu1['name'];
                        if (empty($list[$key1])){
                            $list[$key1] = $this->filterMenuData($menu1);
                            $list[$key1]['matchrule'] = $menuGroup['matchrule'];
                            $list[$key1]['order_num'] = $index1;
                        }
                        if (!empty($menu1['sub_button'])){//存在子菜单
                            foreach ($menu1['sub_button'] as $index2 => $menu2) {
                                $key2 = $menu2['name'].'_'.$menu2['type'];
                                if (empty($list[$key1]['sub_button'][$key2])){
                                    $sub_button = $this->filterMenuData($menu2);
                                    $sub_button['matchrule'] = $menuGroup['matchrule'];
                                    $sub_button['order_num'] = $index2;
                                    $list[$key1]['sub_button'][$key2] = $sub_button;
                                }
                            }
                        }
                    }
                }
            }
        }
        if (!empty($list)){
            Db::beginTransaction();
            try {
                WxMenu::where('menu_id', '>', 0)->delete();
                foreach ($list as $menu1) {
                    $menu1Model = WxMenu::withTrashed()->where('parent_id', 0)->where('name', $menu1['name'])->where('type', $menu1['type'])->first();
                    if (empty($menu1Model)) {
                        $menu1Model = new WxMenu;
                    }
                    $menu1Model->parent_id = 0;
                    $menu1Model->type = $menu1['type'] ?? '';
                    $menu1Model->name = $menu1['name'] ?? '';
                    $menu1Model->key = $menu1['key'] ?? '';
                    $menu1Model->url = $menu1['url'] ?? '';
                    $menu1Model->media_id = $menu1['media_id'] ?? '';
                    $menu1Model->appid = $menu1['appid'] ?? '';
                    $menu1Model->pagepath = $menu1['pagepath'] ?? '';
                    $menu1Model->matchrule = $menu1['matchrule'] ?? [];
                    $menu1Model->is_conditional = !empty($menu1Model->matchrule) ? 1 : 0;
                    $menu1Model->order_num = $menu1['order_num'] ?? 0;
                    $menu1Model->save();
                    $menu1Model->restore();
                    if (!empty($menu1['sub_button'])){
                        $parentId = $menu1Model->menu_id;
                        if (empty($parentId)){
                            throw new \Exception('父级分类ID为空');
                        }
                        foreach ($menu1['sub_button'] as $menu2){
                            $menu2Model = WxMenu::withTrashed()->where('parent_id', $parentId)->where('name', $menu2['name'])->where('type', $menu2['type'])->first();
                            if (empty($menu2Model)) {
                                $menu2Model = new WxMenu;
                            }
                            $menu2Model->parent_id = $parentId;
                            $menu2Model->type = $menu2['type'] ?? '';
                            $menu2Model->name = $menu2['name'] ?? '';
                            $menu2Model->key = $menu2['key'] ?? '';
                            $menu2Model->url = $menu2['url'] ?? '';
                            $menu2Model->media_id = $menu2['media_id'] ?? '';
                            $menu2Model->appid = $menu2['appid'] ?? '';
                            $menu2Model->pagepath = $menu2['pagepath'] ?? '';
                            $menu2Model->matchrule = $menu2['matchrule'] ?? [];
                            $menu2Model->is_conditional = !empty($menu2Model->matchrule) ? 1 : 0;
                            $menu2Model->order_num = $menu2['order_num'] ?? 0;
                            $menu2Model->save();
                            $menu2Model->restore();
                        }
                    }
                }
                Db::commit();
                return true;
            } catch (\Exception $e) {
                Db::rollBack();
                throw new \Exception($e->getMessage());
            }
        }
        return true;
    }
}